package com.cskaoyan.javase.oop1._6constructor;

/**
 * 构造器(constructor),也叫构造方法,是一个概念
 * 创建一个教师类，有课程和年龄两个属性，行为是可以上课。
 * 现在我们需要创建以下对象：
 * 18岁的Java老师对象
 * 28岁的C++老师对象
 * 30岁的Python老师对象
 * ...
 * 按照之前我们的做法，需要先创建出对象，再进行成员变量的赋值。
 * 这样做如果只有一个两个对象还好，如果需要创建很多对象，就有点过于麻烦了。
 * 对象的属性，能不能"出厂"的时候就设定好呢？
 *
 * 有这种需求时，就需要，构造方法（constructor，也叫构造器）来完成了。
 *
 * --------------------------------------------------------------------------
 * 构造器/构造方法的语法:
 * [访问权限修饰符] 类名(形参列表){
 *   // 构造方法体
 * }
 * 它是一个特殊的方法,语法解释:
 *      1.访问权限修饰符还没有学习,这里默认是public
 *      2.构造方法不是一般的方法,它没有返回值,它也不需要返回值,类名取代了它返回值类型的作用
 *          可以将这个类名看成构造器的名字
 *          注: 类名是大驼峰式书写的,连带着构造方法的名字也是大驼峰式书写的
 *      3.形参列表,方法体和一般方法没有大的区别,用起来是一致的.
 *          注: 构造方法和成员方法类似,方法的形参列表中隐含了传参,this关键字!!!
 *
 * 构造器的作用:
 *      1.在Java当中,只要使用new关键字创建对象,那么必然调用类的构造器.
 *          但是构造器不是由程序员主动调用的,程序员也没有办法去主动调用构造器
 *          构造器是jvm创建对象的过程中,jvm去调用,用于给对象的成员变量赋值
 *
 *          总之: 构造器是在创建对象的过程中,用于给对象的成员变量赋值
 *          思考: 构造器是用来创建对象的吗?
 *          不是,对象是jvm自己去创建的,程序员根本管不到
 *              构造器只是用来赋值的,恰好处在创建对象的过程中赋值,和创建对象本身没有关系.
 *
 *      2.构造器不是程序员调用的,但是程序员可以指示JVM调用哪个构造器给成员变量赋值
 *          语法:
 *          new 类名(实参列表);
 *          根据实参列表的不同,调用类的不同构造器
 *
 * 构造器的定义和使用:
 *      1.思考:
 *          我们在学习构造器章节之前,已经使用new关键字创建过对象,那时我们用的是"new Student()"
 *          这里肯定也调用了构造器,调用的是一个无参构造器
 *          而我们没有在类中,定义任何构造器
 *          所以:
 *          在Java的一个类中,如果没有显式的定义一个构造器,那么必然提供默认的无参构造器
 *          默认无参构造的语法:
 *          public 类名(){}
 *
 *      2.显然,无参构造器没有参数,是不能用于给成员变量赋值的,如果想要在创建对象时,用构造器完成赋值,需要使用有参构造器.
 *      注: 一个类中允许有多个构造器,这是方法的重载
 *      有参构造器的标准书写格式:
 *      public 类名(变量1,变量2..){
 *          this.成员变量名 = 局部变量名;
 *          ...
 *      }
 *
 *    3.构造器的赋值
 *    在java中,使用标准格式构造器在创建对象的过程中,  给成员变量的赋值是绝对可靠的,是一定准确的.
 *    这是因为构造器的赋值语句,在所有给成员变量的赋值手段中,是最后被执行的!!!!
 *
 * 注意事项/细节问题:
 *      1.构造器不是用来创建对象的,而是用来在创建对象的过程中,给成员变量赋值的
 *      2.类中如果存在一个显式写出的构造器,那么默认无参就不会提供了.
 *      注: 在Java中,对于一个可能创建对象的类,建议永远手动添加上默认无参,这是一个好习惯
 *
 *      3.标准格式的构造器,格式确实很固定.所以一般情况下,不建议手动写标准格式构造器,直接使用快捷键生成是更好的选择.
 *      快捷键: Alt + Insert
 *      然后选择自动生成构造器(constructor)
 *
 *      4.类中的多个构造器之间是方法的重载关系,尤其记住,方法的形参名字不同,不是方法的重载.
 *
 *      5.构造器就是为了在创建对象过程中,给成员变量赋值用的.没有极其特殊的情况,建议都是直接快捷键生成标准格式构造器
 *      不要在构造器中,写乱七八糟的业务代码
 *      保持构造器的简洁单纯
 *      假如这个类的对象创建,确实需要一个很复杂的逻辑,建议提取方法,然后在构造器中调用方法,不要在构造器这中写很多代码.
 *
 *      6.创建对象和构造器,以及类加载
 *      new对象,new了几个,就调用了几次构造器
 *      (当然每次调用的构造器可以不一样)
 *
 *      但是不管创建了多少次对象,用了几种构造器,类加载始终都只有一次,在第一次创建对象时,触发类加载
 *
 *
 *
 *
 * @since 15:04
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*// 现在我们需要创建以下对象：
        // 18岁的Java老师对象
        Teacher t = new Teacher();
        t.course = "Java";
        t.age = 18;
        // 28岁的C++老师对象
        Teacher t2 = new Teacher();
        t2.course = "C++";
        t2.age = 28;
        // 30岁的Python老师对象
        Teacher t3 = new Teacher();
        t3.course = "Python";
        t3.age = 30;*/

        // 用age构造器创建对象
        Teacher t1 = new Teacher(18);
        Teacher t2 = new Teacher(28, "Java");
        // 18
        System.out.println(t1.age);
        // 28
        System.out.println(t2.age);
        // Java
        System.out.println(t2.course);

        // 类中的无参构造在类有构造器时,不会再提供了
        // Teacher t3 = new Teacher();
    }
}

class Teacher {
    // 课程
    String course = "数学";
    int age = 40;
    String name;

    public void teach() {
        System.out.println("老师教" + course);
    }

    // 默认无参构造器
    public Teacher() {
    }

    public Teacher(String name) {
        this.name = name;
    }

    // public Teacher(String course) {
    //     this.course = course;
    // }

    // age构造器,用于给age赋值
    public Teacher(int age) {
        this.age = age;
    }

    // age和course的双参构造器,用于给course,age同时赋值
    public Teacher(int age, String course) {
        this.age = age;
        this.course = course;
    }


}